//
//  YTXTime.cpp
//  Chart
//
//  Created by CaoJun on 15/2/15.
//
//

#include "YTXTime.h"

using namespace std;
using namespace ytx;

YTXTime :: YTXTime()
{
    struct tm *local;
    time_t t;
    t=time(NULL);
    local=gmtime(&t);
    currentTime = t;
}

YTXTime :: YTXTime(string time)
{
    if (time.size() < 8) {
        // 如果时间字符串长度小于8，则无效
        time = "20000101 00:00:00";
    }
    
    bool onlyDate = time.size() < 17;

    int year = Tools::parseInt(time.substr(0, 4)), month = Tools::parseInt(time.substr(4, 2)), day = Tools::parseInt(time.substr(6, 2));

    int hour = 0, minute = 0, second = 0;

    if(!onlyDate){
        hour = Tools::parseInt(time.substr(9, 2)), minute = Tools::parseInt(time.substr(12, 2)), second = Tools::parseInt(time.substr(15, 2));
    }

    struct tm tminfo = {0};
    tminfo.tm_year = year-1900;
    tminfo.tm_mon = month-1;
    tminfo.tm_mday = day;
    tminfo.tm_hour = hour;
    tminfo.tm_min = minute;
    tminfo.tm_sec = second;
    currentTime = timegm(&tminfo);
}

YTXTime :: YTXTime(time_t currentTime): currentTime(currentTime)
{

}

YTXTime :: YTXTime(int	tm_year,
        int	tm_mon,
        int	tm_mday,
        int	tm_hour,
        int tm_min,
        int	tm_sec)
{
    struct tm tminfo = {0};
    tminfo.tm_year = tm_year-1900;
    tminfo.tm_mon = tm_mon-1;
    tminfo.tm_mday = tm_mday;
    tminfo.tm_hour = tm_hour;
    tminfo.tm_min = tm_min;
    tminfo.tm_sec = tm_sec;
    currentTime = timegm(&tminfo);
}

YTXTime::YTXTime(const YTXTime & ytxtime) : currentTime(ytxtime.getCurrentTime())
{
}

YTXTime YTXTime :: initByGMT8()
{
    YTXTime ytxtime;
    return ytxtime-hours(8);
}
YTXTime YTXTime :: initByGMT8(string time)
{
    YTXTime ytxtime(time);
    YTXTime tt = ytxtime-hours(8);
    return tt;
}
YTXTime YTXTime :: initByGMT8(int	tm_year,
                          int	tm_mon,
                          int	tm_mday,
                          int	tm_hour,
                          int 	tm_min,
                          int	tm_sec)
{
    YTXTime ytxtime(tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec);
    return ytxtime-hours(8);
}

YTXTime YTXTime :: initByDateAndTimeOfDay(YTXTimeDate date, YTXTimeDuration time_of_day)
{
    return YTXTime(date.getYear(), date.getMonth(), date.getDay(), time_of_day.getHour(), time_of_day.getMinute(), time_of_day.getSecond());
}

YTXTime YTXTime :: initByGMT8DateAndGMT8TimeOfDay(YTXTimeDate date, YTXTimeDuration time_of_day)
{
    date = date+hours(8);
    time_of_day = time_of_day+hours(8);
    return YTXTime::initByDateAndTimeOfDay(date, time_of_day)-hours(8);
}

YTXTime YTXTime :: initByDateAndTimeOfDay(YTXTimeDate date, int	tm_hour, int tm_min, int tm_sec)
{
    return YTXTime(date.getYear(), date.getMonth(), date.getDay(), tm_hour, tm_min, tm_sec);
}

YTXTime YTXTime :: initByGMT8DateAndGMT8TimeOfDay(YTXTimeDate date, int	tm_hour, int tm_min, int tm_sec)
{
    return YTXTime(date.getYear(), date.getMonth(), date.getDay(), tm_hour, tm_min, tm_sec)-hours(8);
}

YTXTime YTXTime :: not_a_date_time()
{
    return YTXTime(-1);
}

YTXTime YTXTime :: max_date_time()
{
    return YTXTime(LONG_MAX);
}

YTXTime YTXTime :: min_date_time()
{
    return YTXTime(0);
}

bool YTXTime :: is_not_a_date_time()
{
    return currentTime == -1;
}

int YTXTime :: day_of_week()
{
    struct tm * tminfo = toTM();
    return tminfo->tm_wday;
}

int YTXTime :: day_of_year()
{
    struct tm * tminfo = toTM();
    return tminfo->tm_yday;
}

int YTXTime :: day_of_week_gmt8()
{
    struct tm * tminfo = toGMT8();
    return tminfo->tm_wday;
}

int YTXTime :: day_of_year_gmt8()
{
    struct tm * tminfo = toGMT8();
    return tminfo->tm_yday;
}

YTXTime YTXTime :: start_of_week_since_monday()
{
    int toMonday = day_of_week();

    if (toMonday == 0) {
        toMonday = 7;
    }

    YTXTime monday = *this - days(toMonday-1);

    return monday;
}

YTXTime YTXTime :: start_of_month()
{
    YTXTime data_firstDayOfMonth = YTXTime(getYear(), getMonth(), 1, getHour(), getMinute(), getSecond());

    return data_firstDayOfMonth;
}

YTXTime YTXTime :: end_of_month()
{
    int year = getYear();
    int month = getMonth();
    int day = getDaysInMonth(year, month);
    return YTXTime(year, month, day, getHour(), getMinute(), getSecond());
}

int YTXTime :: getYear()
{
    struct tm * tminfo = toTM();
    return tminfo->tm_year+1900;
}

int YTXTime :: getMonth()
{
    struct tm * tminfo = toTM();
    return tminfo->tm_mon+1;
}

int YTXTime :: getDay()
{
    struct tm * tminfo = toTM();
    return tminfo->tm_mday;
}

int YTXTime :: getHour()
{
    struct tm * tminfo = toTM();
    return tminfo->tm_hour;
}

int YTXTime :: getMinute()
{
    struct tm * tminfo = toTM();
    return tminfo->tm_min;
}

int YTXTime :: getSecond()
{
    struct tm * tminfo = toTM();
    return tminfo->tm_sec;
}

int YTXTime :: getDiffDay()
{
    return (int) (currentTime / 24 / 60 / 60);
}

//格林威治时间
tm * YTXTime :: toTM()
{
    struct tm * tminfo;
    tminfo = gmtime(&currentTime);
    return tminfo;
}

tm * YTXTime :: toGMT8()
{
    struct tm * tminfo;
    YTXTime ytxTime = *this+hours(8);
    tminfo = gmtime(&ytxTime.currentTime);
    return tminfo;
}

YTXTime YTXTime::operator+(long seconds)
{
    return YTXTime(currentTime + seconds);
}

YTXTime YTXTime::operator-(long seconds)
{
    return YTXTime(currentTime - seconds);
}

YTXTime YTXTime::operator+(months m)
{
    struct tm * tminfo;
    tminfo = gmtime(&currentTime);

    int month = tminfo->tm_mon+m.value;
    int nomonth = month % 12;
    int year = (month - nomonth) / 12;

    tminfo->tm_year+= year;
    tminfo->tm_mon= nomonth;

    return timegm(tminfo);
}

YTXTime YTXTime::operator-(months m)
{
    struct tm * tminfo;
    tminfo = gmtime(&currentTime);

    int month = m.value;
    int nomonth = month % 12;
    int year = (month - nomonth) / 12;

    nomonth = tminfo->tm_mon - nomonth;

    if (nomonth < 0) {
        year +=1;
        nomonth = 12+nomonth;
    }

    tminfo->tm_year-= year;
    tminfo->tm_mon = nomonth;

    return timegm(tminfo);
}

YTXTime YTXTime::operator+(years y)
{
    struct tm * tminfo;
    tminfo = gmtime(&currentTime);

    int year = y.value;

    tminfo->tm_year += year;

    return YTXTime(timegm(tminfo));
}

YTXTime YTXTime::operator-(years y)
{
    struct tm * tminfo;
    tminfo = gmtime(&currentTime);

    int year = y.value;

    tminfo->tm_year -= year;

    return YTXTime(timegm(tminfo));

}

long YTXTime :: operator+(YTXTime time)
{
    return currentTime + time.getCurrentTime();
}

long YTXTime :: operator-(YTXTime time)
{
    return currentTime - time.getCurrentTime();
}

bool YTXTime :: operator>(YTXTime time)
{
    return difftime(currentTime, time.getCurrentTime()) > 0;
}

bool YTXTime :: operator<(YTXTime time)
{
    return difftime(currentTime, time.getCurrentTime()) < 0;
}

bool YTXTime :: operator>=(YTXTime time)
{
    return difftime(currentTime, time.getCurrentTime()) >= 0;
}

bool YTXTime :: operator<=(YTXTime time)
{
    return difftime(currentTime, time.getCurrentTime()) <= 0;
}

bool YTXTime :: operator==(YTXTime time)
{
    return difftime(currentTime, time.getCurrentTime()) == 0;
}

bool YTXTime :: operator!=(YTXTime time)
{
    return !(currentTime == time.getCurrentTime());
}


YTXTime YTXTime::operator+=(long seconds)
{
    currentTime += seconds;
    return *this;
}

YTXTime YTXTime::operator-=(long seconds)
{
    currentTime -= seconds;
    return *this;
}

YTXTime YTXTime::operator+=(months m)
{
    currentTime = (*this + m).getCurrentTime();
    return *this;
}

YTXTime YTXTime::operator-=(months m)
{
    currentTime = (*this - m).getCurrentTime();
    return *this;
}

YTXTime YTXTime::operator+=(years y)
{
    currentTime = (*this + y).getCurrentTime();
    return *this;
}

YTXTime YTXTime::operator-=(years y)
{
    currentTime = (*this - y).getCurrentTime();
    return *this;

}

long YTXTime :: toSeconds()
{
    time_t eproch(0);
    return difftime(currentTime, eproch);
}

YTXTime YTXTime :: GMT8()
{
    return *this+hours(8);
}

bool YTXTime :: isLeapYear(){
    struct tm * tminfo;
    tminfo = gmtime(&currentTime);
    return isLeapYear(tminfo->tm_year);
}

int YTXTime :: getDaysInMonth(){
    struct tm * tminfo;
    tminfo = gmtime(&currentTime);
    return getDaysInMonth(tminfo->tm_year, tminfo->tm_mon);
}

string YTXTime :: toStringify(string format, int size)
{
    char ret [size];
    strftime (ret, size, format.c_str(), toTM() );
    return string(ret, size);
}

string YTXTime :: toGTM8Stringify(string format, int size)
{
    char ret [size];
    strftime (ret, size, format.c_str(), toGMT8() );
    return string(ret, size);
}

string YTXTime :: toStringGMT8YYYYMMddHHmmss()
{
    return toGTM8Stringify("%Y%m%d %H:%M:%S", 17);
}

string YTXTime :: toStringGMT8HHmm(){
    return toGTM8Stringify("%H:%M", 5);
}

string YTXTime :: toStringGMT8MMddHHmmss(){
    return toGTM8Stringify("%m%d %H:%M:%S", 13);
}

string YTXTime :: toStringGMT8MMddHHmm(){
    return toGTM8Stringify("%m%d %H:%M", 10);
}

string YTXTime :: toStringGMT8YYYYMMdd(){
    return toGTM8Stringify("%Y%m%d", 8);
}




string YTXTime :: toStringYYYYMMddHHmmss(){
    return toStringify("%Y%m%d %H:%M:%S", 17);
}

string YTXTime :: toStringHHmm(){
    return toStringify("%H:%M", 5);
}

string YTXTime :: toStringMMddHHmmss(){
    return toStringify("%m%d %H:%M:%S", 13);
}

string YTXTime :: toStringMM_ddHHmmss(){
    return toStringify("%m-%d %H:%M:%S", 14);
}

string YTXTime :: toStringMMddHHmm(){
    return toStringify("%m%d %H:%M", 10);
}

string YTXTime :: toStringMM_ddHHmm(){
    return toStringify("%m-%d %H:%M", 11);
}

string YTXTime :: toStringYYYYMMdd(){
    return toStringify("%Y%m%d", 8);
}

string YTXTime :: toStringYYYY_MM_dd(){
    return toStringify("%Y-%m-%d", 10);
}

string YTXTime :: toStringMMdd(){
    return toStringify("%m%d", 4);
}

string YTXTime :: toStringddHHmm(){
    return toStringify("%d %H:%M", 8);
}

bool YTXTime :: isLeapYear(int year)
{
    if (year % 4 != 0) return false;
    if (year % 400 == 0) return true;
    if (year % 100 == 0) return false;
    return true;
}

static int daysInMonths[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

int YTXTime :: getDaysInMonth(int year, int month)
{
    int days = daysInMonths[month];

    if (month == 1 && isLeapYear(year)) // February of a leap year
        days += 1;

    return days;
}

YTXTime YTXTime :: time_of_day()
{
    return YTXTime( 1970, 1, 1, getHour(), getMinute(), getSecond() );
}

YTXTime YTXTime :: date()
{
    return YTXTime( getYear(), getMonth(), getDay(), 0,0,0 );
}
